<?php

declare(strict_types=1);

namespace App\CustHub\Service;

use App\Common\Service\ExcelService;
use App\CustHub\Constants\ContactTaskCenterTyperConstants;
use App\CustHub\Constants\TagModuleConstants;
use App\CustHub\Dto\ContactTcContentDto;
use App\CustHub\Helpers\BcMath;
use App\CustHub\Mapper\ChSmartTagMapper;
use App\CustHub\Model\ChSmartTag;
use App\CustHub\Model\ChSmartTagContactStat;
use Carbon\Carbon;
use Hyperf\DbConnection\Db;
use Mine\Abstracts\AbstractService;
use Mine\Annotation\Transaction;
use Mine\Exception\NormalStatusException;
use Mine\MineModel;
use Psr\Http\Message\ResponseInterface;
use function Hyperf\Collection\collect;
use function Hyperf\Collection\data_get;

/**
 * 智能标签
 */
class ChSmartTagService extends AbstractService
{
    public $mapper;

    public function __construct(ChSmartTagMapper $mapper)
    {
        $this->mapper = $mapper;

    }

    /**
     * 根据用户ID和标签组ID获取标签列表
     * @param mixed $mainUid
     * @param mixed $module
     * @param mixed $pageSize
     * @return array
     */
    public function getListByUidAndGroupId(array $data): array
    {
        $mainUid = $data['main_uid'];
        $module = $data['module'];
        $pageSize = $data['page_size'] ?? 10;
        $name = $data['name'] ?? '';

        $paginate = $this->mapper->model::query()
            ->select(['id', 'name', 'module', 'is_preset', 'sub_type', 'duration', 'unit'])
            ->with(['tags' => function ($query) use ($name){
                $query->select(['id', 'name', 'parent_id', 'contact_cnt'])->when(function ($query) use ($name){
                    $query->where('name','like',"%{$name}%");
                });
            }])
            ->where('main_uid', $mainUid)
            ->where('module', $module)
            ->where('parent_id', 0)
            ->when(!empty($name),function ($query) use ($name){
                $query->where(function ($query) use ($name){
                    $query->where('name','like',"%{$name}%")
                        ->orWhereHas('tags',function ($query) use ($name){
                            $query->where('name','like',"%{$name}%");
                        });
                });
            })
            ->paginate((int)$pageSize);

        $data = $this->mapper->setPaginate($paginate);
        $list = collect($data['items'])->toArray();
        $list = collect($list)->map(function ($item) use ($name) {

            if(!empty($name) && empty($item['tags'])){
                $item['tags'] = $this->mapper->model::query()
                    ->select('id', 'name', 'parent_id', 'contact_cnt')
                    ->where('parent_id',$item['id'])
                    ->get()->toArray();
            }

            $totalContactCnt = array_sum(array_column($item['tags'], 'contact_cnt'));
            $item['total_contact_cnt'] = $totalContactCnt;
            $item['tags'] = collect($item['tags'])->map(function ($item) use ($totalContactCnt) {
                if ($totalContactCnt == 0) {
                    $item['contact_rate'] = 0;
                } else {
                    $item['contact_rate'] = BcMath::round($item['contact_cnt'] / $totalContactCnt * 100, 2);
                }
                return $item;
            })->all();
            if ($item['module'] != TagModuleConstants::BEHAVIOR) {
                unset($item['sub_type']);
            }

            if ($item['module'] != TagModuleConstants::TIME_PROCESS) {
                unset($item['duration'], $item['unit']);
            }
            unset($item['module']);
            return $item;
        })->all();
        $data['items'] = $this->changeData($list);
        unset($list);
        return $data;
    }


    private function changeData(array $list)
    {
        foreach ($list as $k=>$item){
            if(!isset($item['parent_id'])){
                $list[$k]['selectable'] = false;
            }
            $list[$k]['scopedSlots'] = [
                'title' => 'custom'
            ];
            if(!empty($item['tags'])){
                $list[$k]['tags'] = $this->changeData($item['tags']);
            }
        }
        return $list;
    }

    /**
     * 标签新增
     * @param array $data
     * @return mixed
     */
    #[Transaction]
    public function save(array $data): mixed
    {
        if ($data['module'] == TagModuleConstants::LIFE_CYCLE) {
            throw new NormalStatusException('生命周期标签不允许手动添加');
        }

        if ($this->mapper->checkExistByName($data['name'], 0)) {
            throw new NormalStatusException('分组名重复');
        }

        $groupCount = $this->mapper->getCountByModule($data['main_uid'], $data['module']);
        if ($groupCount + 1 > 100) {
            throw new NormalStatusException('分组数量已达上限');
        }

        $parentId = $this->mapper->save($data);
        $subType = data_get($data, 'sub_type', 0);

        $tagCount = count($data['tags']);
        if ($tagCount > 100) {
            throw new NormalStatusException('标签数量已达上限');
        }

        $childData = $this->changeTagData($data['tags'], $data['uid'], $data['main_uid'], $parentId, $data['module'], $subType);
        $this->batchSave($childData);
        return $parentId;
    }

    /**
     * 标签修改
     * @param mixed $id
     * @param array $data
     * @return bool
     */
    public function update(mixed $id, array $data): bool
    {

        $info = $this->mapper->model::query()
            ->where('id', $id)
            ->where('main_uid', $data['main_uid'])
            ->first();
        if (empty($info)) {
            throw new NormalStatusException('当前信息不存在');
        }

        $isGroup = $info->parent_id == 0;

        $parentId = $isGroup ? 0 : null;

        if ($this->mapper->checkExistByName($data['name'], $parentId, $id)) {
            throw new NormalStatusException($isGroup ? '分组名重复' : '标签名称重复');
        }

        $info->name = $data['name'];
        $rst = $info->save();
        return $rst;
    }

    /**
     * 批量新增标签
     * @param array $data
     * @return bool
     */
    public function batchSaveTag(array $data): bool
    {
        $info = $this->mapper->model::query()
            ->where('id', $data['group_id'])
            ->where('main_uid', $data['main_uid'])
            ->first();
        if (empty($info) || $info->parent_id != 0) {
            throw new NormalStatusException('请选择分组后新增标签');
        }

        $parentId = $data['group_id'];

        $tagCount = count($data['tags']);
        $beforeTagCount = $this->mapper->getCountByModule($data['main_uid'], $info->module, $parentId);
        if ($tagCount + $beforeTagCount > 100) {
            throw new NormalStatusException('标签数量已达上限');
        }

        $childData = $this->changeTagData($data['tags'], $data['uid'], $data['main_uid'], $parentId, $info->module, $info->sub_type);
        return $this->batchSave($childData);
    }

    /**
     * 删除标签组
     * @param array $data
     * @return mixed
     * @throws \Exception
     */
    #[Transaction]
    public function deleteTagGroup(array $data): mixed
    {
        $info = $this->mapper->model::query()
            ->where('id', $data['id'])
            ->where('main_uid', $data['uid'])
            ->first();
        if (empty($info)) {
            throw new NormalStatusException('删除失败');
        }

        if ($info->parent_id == 0 && $info->module == TagModuleConstants::LIFE_CYCLE) {
            throw new NormalStatusException('删除失败');
        }

        $rst = $info->delete();
        if ($rst) {
            $this->mapper->model::query()
                ->where('parent_id', $data['id'])
                ->delete();
        }
        return $rst;
    }

    /**
     * @param array $data
     * @return bool|int|mixed|null
     * @throws \Exception
     */
    public function batchDeleteTag(array $data): mixed
    {
        $rst = $this->mapper->model::query()
            ->whereIn('id', $data['ids'])
            ->where('main_uid', $data['main_uid'])
            ->where('parent_id', '<>', 0)
            ->delete();
        return $rst;
    }

    /**
     * 标签排序
     * @param array $params
     */
    public function sort(array $params)
    {
        $type = data_get($params, 'type', 'up');
        // 获取当前标签
        $currentTag = ChSmartTag::find($params['id'], ['id', 'parent_id', 'sort']);

        if (!$currentTag) {
            throw new NormalStatusException('操作失败');
        }

        $parentId = $currentTag->parent_id;

        // 根据类型进行排序处理
        switch ($type) {
            case 'up':
                $this->moveUp($currentTag, $parentId);
                break;

            case 'down':
                $this->moveDown($currentTag, $parentId);
                break;

            case 'top':
                $this->moveToTop($currentTag, $parentId);
                break;

            case 'bottom':
                $this->moveToBottom($currentTag, $parentId);
                break;

            default:
               throw new NormalStatusException('无效的操作类型');
        }
    }


    private function moveUp($currentTag, $parentId)
    {
        // 获取同一parent_id下比当前sort值小的最大记录
        $previousTag = ChSmartTag::where('parent_id', $parentId)
            ->where('sort', '<', $currentTag->sort)
            ->orderByDesc('sort')
            ->first(['id', 'sort']);

        if ($previousTag) {
            // 交换sort值
            Db::transaction(function () use ($currentTag, $previousTag) {
                $tempSort = $currentTag->sort;
                $currentTag->sort = $previousTag->sort;
                $previousTag->sort = $tempSort;

                $currentTag->save();
                $previousTag->save();
            });
        }
    }

    private function moveDown($currentTag, $parentId)
    {
        // 获取同一parent_id下比当前sort值大的最小记录
        $nextTag = ChSmartTag::where('parent_id', $parentId)
            ->where('sort', '>', $currentTag->sort)
            ->orderBy('sort')
            ->first(['id', 'sort']);

        if ($nextTag) {
            // 交换sort值
            Db::transaction(function () use ($currentTag, $nextTag) {
                $tempSort = $currentTag->sort;
                $currentTag->sort = $nextTag->sort;
                $nextTag->sort = $tempSort;

                $currentTag->save();
                $nextTag->save();
            });
        }
    }

    private function moveToTop($currentTag, $parentId)
    {
        Db::transaction(function () use ($currentTag, $parentId) {
            ChSmartTag::where('parent_id', $parentId)
                ->where('sort', '<', $currentTag->sort)
                ->increment('sort');

            ChSmartTag::where('id', $currentTag->id)->update(['sort' => 0]);
        });
    }

    private function moveToBottom($currentTag, $parentId)
    {
        $maxSort = ChSmartTag::where('parent_id', $parentId)->max('sort');

        Db::transaction(function () use ($currentTag, $parentId, $maxSort) {
            ChSmartTag::where('parent_id', $parentId)
                ->where('sort', '>', $currentTag->sort)
                ->decrement('sort');

            ChSmartTag::where('id', $currentTag->id)->update(['sort' => $maxSort]);
        });
    }


    public function selectList(array $params)
    {
        $exclude_module = data_get($params,'exclude_module');
        $list = ChSmartTag::query()
            ->select(['id','name','parent_id'])
            ->where('uid',$params['uid'])
            ->when(!empty($params['name']),function ($query) use ($params){
                $query->where('name','like','%'.$params['name'].'%');
            })
            ->when(!empty($exclude_module),function ($query) use ($exclude_module){
                $query->where('module','<>',$exclude_module);
            })
            ->orderBY('sort')
            ->get()->toTree();
        return $list;
    }

    private function changeTagData(array $tags, mixed $uid, mixed $mainUid, mixed $parentId, $module, mixed $subType = 0)
    {
        $childData = [];
        foreach ($tags as $k => $item) {
            if ($this->mapper->checkExistByName($item)) {
                throw new NormalStatusException('标签名称重复');
            }
            $childData[$k]['name'] = $item;
            $childData[$k]['uid'] = $uid;
            $childData[$k]['main_uid'] = $mainUid;
            $childData[$k]['module'] = $module;
            $childData[$k]['parent_id'] = $parentId;
            $childData[$k]['sort'] = $k;
            $childData[$k]['sub_type'] = $subType;
        }
        return $childData;
    }

    /**
     * 添加客户标签关联
     * @param array $data
     * @return bool
     */
    public function addContact(array $data): bool
    {
        $id = $data['id'];
        $contactId = json_decode($data['contact_ids'],true);

        $model = ChSmartTag::find($id);
        if(empty($model)){
            throw new NormalStatusException('添加失败');
        }

        $content = new ContactTcContentDto();
        $content->setContactIds($contactId);
        $content->setTagIds([$id]);
        //标签变记录
        container()->get(ChSmartTagChangeLogService::class)->saveLog($id,$contactId);
        return container()->get(ChContactTaskCenterService::class)->addTask($data['uid'],$data['main_uid'],ContactTaskCenterTyperConstants::PUT_ON_SMART_TAG,$content);
    }

    /**
     * 标签里删除客户
     * @param array $data
     * @return bool
     */
    public function delContact(array $data): bool
    {
        $id = $data['id'];
        $contactId = json_decode($data['contact_ids'],true);

        $model = ChSmartTag::find($id);
        if(empty($model)){
            throw new NormalStatusException('删除失败');
        }

        $content = new ContactTcContentDto();
        $content->setContactIds($contactId);
        $content->setRemoveTagIds([$id]);

        return container()->get(ChContactTaskCenterService::class)->addTask($data['uid'],$data['main_uid'],ContactTaskCenterTyperConstants::DELETE_SMART_TAG,$content);
    }

    /**
     * 移动客户
     * @param array $data
     * @return bool
     */
    public function moveContact(array $data): bool
    {
        $id = $data['remove_id'];
        $moveTagIds = json_decode($data['move_tag_ids'],true);
        $contactId = json_decode($data['contact_ids'],true);

        $model = ChSmartTag::find($id);
        if(empty($model)){
            throw new NormalStatusException('移动失败');
        }

        $content = new ContactTcContentDto();
        $content->setContactIds($contactId);
        $content->setTagIds($moveTagIds);
        $content->setRemoveTagIds([$id]);

        foreach ($moveTagIds as $tagId){
            container()->get(ChSmartTagChangeLogService::class)->saveLog($tagId,$contactId);
        }

        return container()->get(ChContactTaskCenterService::class)->addTask($data['uid'],$data['main_uid'],ContactTaskCenterTyperConstants::MOVE_SMART_TAG,$content);
    }


    /**
     * 获取标签占比数据
     * @param array $params
     * @return array
     */
    public function getTagProportionData(array $params): array
    {
        $tagList = ChSmartTag::query()
            ->select(['id','name','contact_cnt'])
            ->where('parent_id',$params['tag_group_id'])
            ->pluck('contact_cnt','name')
            ->toArray();
        return calculatePercentages($tagList);
    }

    /**
     * 对比昨日
     * @param array $params
     * @return array
     */
    public function getYesterdayComparisonData(array $params)
    {

        $tagList = ChSmartTag::query()
            ->select(['id','name','contact_cnt'])
            ->where('parent_id',$params['tag_group_id'])
            ->get()
            ->toArray();

        $yesterday = Carbon::now()->subDay()->toDateString();

        $yesterdayTagList = ChSmartTagContactStat::query()
            ->where('date',$yesterday)
            ->where('tag_group_id',$params['tag_group_id'])
            ->pluck('contact_count','tag_id')
            ->toArray();

        $list = [];
        foreach ($tagList as $item){
            $yesterdayCount = $yesterdayTagList[$item['id']] ?? 0;
            $todayCount = $item['contact_cnt'];
            list($roundedTodayRatio,$roundedYesterdayRatio) = $this->calculateRatio($todayCount,$yesterdayCount);
            $list[$item['name']] = [
                '今日' => $roundedTodayRatio,
                '昨日' => $roundedYesterdayRatio
            ];
        }
        return $list;
    }


    public function getDailyStats(array $params)
    {
        $pageSize = $params['page_size'] ?? MineModel::PAGE_SIZE;
        $startDate = data_get($params,'start_date');
        $endDate = data_get($params,'end_date');

        // 获取最新日期下的所有 tag_id
        $tagIdMap = $this->mapper->model::query()
            ->select(['id','name'])
            ->where('parent_id',$params['tag_group_id'])
            ->pluck('name','id')
            ->toArray();

        $header = [];
        foreach ($tagIdMap as $tagId=>$tagName){
            $header[] = [
                'title' => $tagName,
                'key' => 'tag_'.$tagId
            ];
        }

        // 动态生成每个 tag_id 的统计列
        $selectFields = [
            Db::raw("date"),
        ];
        foreach ($tagIdMap as $tagId=>$tagName) {
            $selectFields[] = Db::raw(
                "SUM(CASE WHEN tag_id = {$tagId} THEN contact_count ELSE 0 END) AS `tag_{$tagId}`"
            );
        }

        // 执行查询，仅统计最新日期的数据
        $data = Db::table('ch_smart_tag_contact_stats')
            ->select($selectFields)
            ->where('tag_group_id', $params['tag_group_id'])
            ->when(!empty($startDate) && !empty($endDate),function ($query) use ($startDate,$endDate){
                $query->whereBetween('date', [$startDate, $endDate]);
            })
            ->groupBy('date')
            ->orderBy('date','desc')
            ->paginate((int) $pageSize);

        $result = $this->mapper->setPaginate($data);
        $result['header'] = $header;
        return $result;
    }

    /**
     * 导出数据看板分日数据
     * @param array $params
     * @return ResponseInterface
     */
    public function exportDailyStats(array $params): ResponseInterface
    {
        $startDate = data_get($params,'start_date');
        $endDate = data_get($params,'end_date');

        // 获取最新日期下的所有 tag_id
        $tagIdMap = $this->mapper->model::query()
            ->select(['id','name'])
            ->where('parent_id',$params['tag_group_id'])
            ->pluck('name','id')
            ->toArray();

        $headerData = [
            'date'=> [
                'value' => '日期'
            ]
        ];
        foreach ($tagIdMap as $tagId=>$tagName){
            $headerData['tag_'.$tagId] = [
                'value' => $tagName
            ];
        }

        // 动态生成每个 tag_id 的统计列
        $selectFields = [
            Db::raw("date"),
        ];
        foreach ($tagIdMap as $tagId=>$tagName) {
            $selectFields[] = Db::raw(
                "SUM(CASE WHEN tag_id = {$tagId} THEN contact_count ELSE 0 END) AS `tag_{$tagId}`"
            );
        }

        // 执行查询，仅统计最新日期的数据
        $data = ChSmartTagContactStat::query()
            ->select($selectFields)
            ->where('tag_group_id', $params['tag_group_id'])
            ->when(!empty($startDate) && !empty($endDate),function ($query) use ($startDate,$endDate){
                $query->whereBetween('date', [$startDate, $endDate]);
            })
            ->groupBy('date')
            ->orderBy('date','desc')
            ->get()->toArray();
        $excelService = new ExcelService($headerData);
        return $excelService->export('分日数据',$data);
    }

    private function calculateRatio($todayCount, $yesterdayCount): array
    {
        // 总人数
        $totalCount = $todayCount + $yesterdayCount;

        // 如果总人数为0，返回占比为0
        if ($totalCount == 0) {
            return [0, 0];
        }

        // 计算占比
        $todayRatio = ($todayCount / $totalCount) * 100;
        $yesterdayRatio = ($yesterdayCount / $totalCount) * 100;

        // 四舍五入到小数点后2位
        $roundedTodayRatio = round($todayRatio, 2);
        $roundedYesterdayRatio = round($yesterdayRatio, 2);

        // 调整占比使得总和为100
        $difference = 100 - ($roundedTodayRatio + $roundedYesterdayRatio);
        if ($difference > 0) {
            // 如果差值大于0，调整今天占比
            $roundedTodayRatio += $difference;
        }

        return [$roundedTodayRatio, $roundedYesterdayRatio];
    }

    public function getTagsByIds($ids)
    {
        return $this->mapper->getModel() ->  newQuery() -> whereIn('id',$ids) -> pluck('name');
    }
}